/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proyecto;

/**
 *
 * @author Luis Romero
 */
import java.util.logging.Level;
import java.util.logging.Logger;
import static proyecto.Constantes.*;

public class ID extends Thread {

    EX SIG;
    IF ANT;
    SharedMem MInt;
    Registros Reg;
    boolean repite;
    final Object lock;
    Nucleo N;
    Reloj reloj;

    ID(Registros r) {
        MInt = new SharedMem();
        Reg = r;
        this.setName("ID");
        repite = true;
        lock = new Object();
    }

    public void parar() {
        synchronized (lock) {
            try {
                //System.out.println("Parar ID");
                lock.wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(ID.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void seguir() {
        synchronized (lock) {
            lock.notify();
            // System.out.println("Seguir ID");
        }
    }

    public void setEtapa(IF fetch, EX ex) {
        SIG = ex;
        ANT = fetch;
    }

    public void setReloj(Reloj reloj){
        this.reloj = reloj;
    }
    
    public void setRegistros(Registros reg) {
        Reg = reg;
    }

    public void setNucleo(Nucleo n) {
        N = n;
    }

    public synchronized int pedirRegistro(int r) {
        int retorno = Reg.getRegistro(r);
        //Reg.invalidarRegistro(r);
        return retorno;
    }

    public void run() {
        //Determina el tipo de instruccion
        //Lee los registros y los coloca en A,B y el valor de Imm
        System.out.println("Inicio ID");
        N.seguir();
        this.parar();
        while (repite) {
            //N.seguir();
            // this.parar();
            int valor1;
            int valor2;
            System.out.println("ID: " + MInt.getReg(INST) + MInt.getReg(REGF1) + MInt.getReg(REGF2) + MInt.getReg(REGD));
            SIG.MInt.setReg(INST, MInt.getReg(INST));
            SIG.MInt.setReg(REGD, MInt.getReg(REGD));
            SIG.MInt.setReg(REGF1, MInt.getReg(REGF1));
            SIG.MInt.setReg(REGF2, MInt.getReg(REGF2));

            switch (MInt.getReg(INST)) {
                case DADDI:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGIMM, MInt.getReg(REGF2));
                    break;
                case DADD:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    valor2 = pedirRegistro(MInt.getReg(REGF2));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGB, valor2);
                    break;
                case DSUB:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    valor2 = pedirRegistro(MInt.getReg(REGF2));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGB, valor2);
                    break;
                case DMUL:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    valor2 = pedirRegistro(MInt.getReg(REGF2));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGB, valor2);
                    break;
                case DDIV:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    valor2 = pedirRegistro(MInt.getReg(REGF2));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGB, valor2);
                    break;
                case LW:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGIMM, MInt.getReg(REGF2));
                    break;
                case SW:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    //Reg.invalidarRegistro(MInt.getReg(REGD));
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGIMM, MInt.getReg(REGF2));
                    SIG.MInt.setReg(REGB, Reg.getRegistro(MInt.getReg(REGD)));//Rev
                    break;
                case BEQZ:
                    if (Reg.getRegistro(MInt.getReg(REGF1)) == 0) {
                        ANT.PC = ANT.PC + (MInt.getReg(REGF2) * 4);
                        SIG.MInt.setReg(INST, 0);
                        SIG.MInt.setReg(REGD, 0);
                        SIG.MInt.setReg(REGF1,0);
                        SIG.MInt.setReg(REGF2,0);
                    }
                    break;
                case BNEZ:
                     if (Reg.getRegistro(MInt.getReg(REGF1)) != 0) {
                        ANT.PC = ANT.PC + (MInt.getReg(REGF2) * 4);
                        SIG.MInt.setReg(INST, 0);
                        SIG.MInt.setReg(REGD, 0);
                        SIG.MInt.setReg(REGF1,0);
                        SIG.MInt.setReg(REGF2,0);
                    }
                    break;
                case JAL:
                    Reg.setRegistro(31, ANT.PC);
                    ANT.PC = ANT.PC + (MInt.getReg(REGF1)*4);
                    SIG.MInt.setReg(INST, 0);
                    SIG.MInt.setReg(REGD, 0);
                    SIG.MInt.setReg(REGF1,0);
                    SIG.MInt.setReg(REGF2,0);
                    break;
                case JR:
                    ANT.PC = Reg.getRegistro(MInt.getReg(REGF1));
                    SIG.MInt.setReg(INST, 0);
                    SIG.MInt.setReg(REGD, 0);
                    SIG.MInt.setReg(REGF1,0);
                    SIG.MInt.setReg(REGF2,0);
                    break;
                case LL:
                    valor1 = pedirRegistro(MInt.getReg(REGF1));
                    Reg.invalidarRegistro(MInt.getReg(REGD));
                    Reg.invalidarRegistro(32);
                    SIG.MInt.setReg(REGA, valor1);
                    SIG.MInt.setReg(REGIMM, MInt.getReg(REGF2));
                    break;
                case SC:
                    if(Reg.getRegistro(32)==MInt.getReg(REGF2)+Reg.getRegistro(MInt.getReg(REGF1))){
                        Reg.invalidarRegistro(MInt.getReg(REGD));
                        valor1 = pedirRegistro(MInt.getReg(REGF1));
                        SIG.MInt.setReg(REGA, valor1);
                        SIG.MInt.setReg(REGIMM, MInt.getReg(REGF2));
                        SIG.MInt.setReg(REGB, Reg.getRegistro(MInt.getReg(REGD)));
                    }else{
                        Reg.setRegistro(MInt.getReg(REGD),0);
                        SIG.MInt.setReg(INST, 0);
                        SIG.MInt.setReg(REGD, 0);
                        SIG.MInt.setReg(REGF1,0);
                        SIG.MInt.setReg(REGF2,0);
                    }
                    break;
                case FIN:
                    repite = false;
                    break;
                case INTERRUPT:
                    SIG.MInt.setReg(INST, INTERRUPT);
                    SIG.MInt.setReg(NPC, MInt.getReg(NPC));
                    repite = false;
                    break;
            }

            reloj.cuentaHilo(1);
            reloj.seguir();
            //Llamar a ejecutar al siguiente hilo EX
            SIG.seguir();
            this.parar();
            ANT.seguir();
            this.parar();
            if(!repite){
                SIG.seguir();
            }
            //SIG.seguir();
            //this.parar();

        }
        //this.seguir();
        System.out.println("Murio ID");
    }
}
